Vipps payment flow using Azure AD B2C
Introduction
The first part of this guide will describe how to implement a simple payment flow where a user can pay for an order and give consent to sharing user info without the need of being signed in. The second part will show how the payment can be used to get information to store a user in Azure AD B2C.
The code snippets are using the .NET SDK to communicate with the API platform. By following these steps, a user can pay for an order and later use Vipps Login to get an overview of his/her orders.
Prerequisites
Register a web application to use the Microsoft Graph API
Create a test unit in the Vipps portal.
- Save the
client_id
andclient_secret
for use in later steps.
- Save the
Add the Vipps configuration to Program.cs.
var vippsConfigurationOptions = new VippsConfigurationOptions
{
ClientId = "CLIENT-ID",
ClientSecret = "CLIENT-SECRET",
MerchantSerialNumber = "MERCHANT-SERIAL-NUMBER",
SubscriptionKey = "SUBSCRIPTION-KEY",
UseTestMode = true
};Note: The above example is for illustrating what parameters should be set in the
VippsConfigurationOptions
. Make sure to store your client credentials safely!If you are developing in the production environment, do not include
UseTestMode
.For further explanation, refer to the SDKs section.
Sequence Diagram
The Azure AD B2C payment flow consists of:
- Initiating a payment session
- Storing user in Azure AD B2C
Initiate payment session with profile sharing
To initiate a payment, the merchant backend requires the ePayment API to create a payment endpoint. The endpoint will return a redirect URL. The redirect URL is where the user is sent to confirm the payment. The Return URL is the URL that the user will be sent to after a successful payment. For example, an order confirmation page/endpoint.
The parameters needed to create a payment are:
- Phone Number: The phone number of the user
- Amount: The payment amount
- Payment Description: Description of what the user is paying for
- Reference: An unique identifier for an order
Scope defines the information you are requesting from the user. Additional scopes provided by Vipps can be added by adding them to the Scope string in the ProfileRequest.
public async Task<string> CreatePayment(string phoneNumber, long amount, string paymentDescription, string reference)
{
var request = new CreatePaymentRequest
{
Amount = new Amount
{
Value = amount,
Currency = Currency.NOK
},
PaymentMethod = new PaymentMethod
{
Type = PaymentMethodType.WALLET
},
Customer = new Customer
{
PhoneNumber = phoneNumber
},
Reference = reference ,
UserFlow = CreatePaymentRequestUserFlow.WEB_REDIRECT,
ReturnUrl = "<ReturnURL>",
PaymentDescription = paymentDescription,
Profile = new ProfileRequest
{
Scope = "name phoneNumber birthDate"
}
};
var result = await EpaymentService.CreatePayment(request);
return result.RedirectUrl.ToString();
}
See the ePayment API spec for more details.
Store user in Azure AD B2C
If the user confirms the payment and gives consent to user information, he/she will be redirected to the ReturnURL
. The merchant is now able to collect user information and store it in Azure AD B2C. In this part, the merchant must do the following:
- Get the payment by the reference, and collect the user's sub
- Use the sub to collect user information
- Store the user information in Azure AD B2C
Get sub from Vipps Payment
public async Task<string> GetSubFromVippsPayment(string reference)
{
var request = await EpaymentService.GetPayment(reference);
return request.Profile.Sub;
}
The sub
is an identifier provided by Vipps that will be unique to a given user. For more information about the sub
, see What is the sub?
Use the sub to collect user information
To get user information, you will have to use the Login API which is not supported by the SDK. Here, you must configure an HttpClient where you must add a Bearer token in the authorization header. You can get the access token by following the Access token API guide or use the SDK like this:
public async Task<User?> GetUserInfo(string sub)
{
var accessToken = await AccessTokenService.GetAccessToken();
HttpClient client = CreateHttpClient(); // Safely create http client
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {accessToken}");
var response = await client.GetAsync($"<base_url>/vipps-userinfo-api/userinfo/{sub}");
if (!response.IsSuccessStatusCode)
{
return null;
}
var body = await response.Content.ReadAsStringAsync();
User? user = JsonConvert.DeserializeObject<User>(body);
return user;
}
Store the user information in Azure AD B2C
Once user info has been received from Vipps, you can create and store the users in Azure AD B2C. This can be done through the Microsoft Graph API. An example of how this can be implemented using the Microsoft Graph .NET Client Library is shown below. You must change <Vipps environment>
to the Vipps environment your are using. This could be either api.vipps.no (Prod) or apitest.vipps.no (Test).
private async Task PostUser(GraphServiceClient graphClient,string sub, string name, string email, string phoneNumber)
{
var requestBody = new Microsoft.Graph.Models.User
{
DisplayName = name,
MobilePhone = phoneNumber,
UserPrincipalName = email,
Identities = new List<ObjectIdentity>
{
new ObjectIdentity
{
SignInType = "federated",
Issuer = "https://<Your vipps environment>/access-management-1.0/access/",
IssuerAssignedId = sub,
},
},
};
var result = await graphClient.Users.PostAsync(requestBody);
}
Make sure that the parameters in ObjectIdentity
are set to the same values as in the example and that IssuerAssignedId
is set to the sub
value received from the Vipps API.
Note: before PostAsync
can be called, make sure that there are no other users already registered with the same combination of Issuer
and IssuerAssignedId
.
An example of how to receive a user from B2C is shown below.
private async Task<Microsoft.Graph.Models.User?> GetAzureB2CUser(GraphServiceClient graphClient, string sub)
{
var response = await graphClient.Users
.GetAsync(requestConfiguration =>
{
requestConfiguration.QueryParameters.Filter =
$"identities/any(c:c/issuerAssignedId eq '{sub}' and issuer eq 'https://<Your vipps environment>/access-management-1.0/access/')";
});
return response?.Value?.FirstOrDefault();
}
This can be used to check if a user has already been created.
Note about custom policies
It could be possible to implement a Vipps payment flow while storing users in B2C as a custom policy, similar to Vipps login using a custom policy. One could create multiple policies for each step in the payment process that is called sequentially, but since there currently is no support for passing parameters to a custom policy before it is called, this flow will require a backend. Ultimately, this means that it is arguably more cumbersome to use custom policies rather than using the Vipps APIs directly.
References
Implementing a payment flow
Storing users in Azure AD B2C
Terminology