> **Description:** Learn how to implement the Login API in your website with detailed integration steps and code examples.

# Login from a website

API version: 2.0

In the *Login from a website* flow, the user initiates their first login by entering their phone number on the landing page.
They select whether to be remembered in the browser and then give consent to sharing their information with the merchant, if needed.

Here is the customer experience for their first login:

  A user chooses to log in with Vipps or MobilePay on a merchant site.
  If required, the user enters their phone number on the Vipps or MobilePay landing page, or is taken directly to the app.
  The user confirms the login in the Vipps or MobilePay app.
  The user gives consent to what information will be shared with the merchant.
  The user is logged in on the merchant's site.

From the website, they will see screens similar to these:

Screenshot: Three-step desktop login flow (Vipps or MobilePay). Left: the merchant's login page with a "Continue with Vipps" button. Center: a Vipps modal with a phone number entry field and a "Remember me in browser" checkbox. Right: a confirmation screen displaying a code number and instructing the user to open the app and follow the prompts.

Then, they will go to the Vipps or MobilePay app and confirm the login:

Screenshot: Four mobile screens showing the app-side confirmation step (Vipps or MobilePay). Left to right: an iPhone home screen with a push notification asking the user to confirm a login; the Vipps app loading; a number-selection screen showing three choices for the user to match against the code displayed in the desktop browser; and a "Return to the browser or app you started in" screen.

They are authenticated in the browser and can provide consent, if required.

Then the user can be redirected back to the redirect URI, if provided by merchant:

Screenshot: Two desktop screens showing the final steps of the login flow (Vipps or MobilePay). Left: a consent screen listing the user's name, phone number, and email, with a "Continue" button to accept data sharing with the merchant. Right: the merchant's welcome page confirming the user is now logged in.

For an extended illustration of this sequence, see:

* [How it works: Login from desktop](https://developer.vippsmobilepay.com/docs/APIs/login-api/how-it-works/login-from-desktop.md)

## Remembered flow

The user can choose to be remembered in the browser, enabling automatic sign-ins for later visits.
If a user has chosen to be remembered in the browser, then they don't need to go to the app.

The user will either be asked to provide consent to share profile information or be logged in directly.

  A user chooses to log in with Vipps or MobilePay on a merchant site.
  If consent has not already been given, the user is asked to consent to sharing information with the merchant (shown as an optional step).
  The user is logged in on the merchant's site.

If the user is remembered in the browser, then only the consent flow will be completed.
If the user already has provided consent, then this step will also be skipped, allowing a direct login experience.

## Plugins

For *Login from a website*, there are Vipps MobilePay plugins available for some platforms.
For instance:

* [Login module for Adobe Commerce / Magento](https://developer.vippsmobilepay.com/docs/plugins-ext/login-magento/README.md)
* [Vipps/MobilePay Login for WordPress and WooCommerce](https://developer.vippsmobilepay.com/docs/plugins-ext/login-wordpress/README.md)

To get help with this from a partner, go to [Find a partner](https://vippsmobilepay.com/en-NO/partners-and-plugins?type=partners).

## Manual integration

This section contains information necessary to perform a manual integration with
Login. This **should not be attempted without a solid grasp of the OAuth2
and OpenID Connect standards**. All endpoints needed for integration can be found in our OpenID connect discovery endpoint.
These endpoints should be fetched dynamically by your application, since they are prone to change.

**TIP**

If a plugin is not available, the easiest - and **strongly recommended** - way to integrate with the service
is to use a well renowned OAuth2.0/OpenID Connect Library for your programming language.

We don't recommend any specific library, but the
[certified OpenID developer tools](https://openid.net/developers/certified/) page
is a good starting point.

**WARNING**

Login in browser should only be run in the browser window using redirects.
iFrame is not supported, and new window is not recommended.

### Call by call

The following is a very basic case, starting with a user clicking *Log in with Vipps/MobilePay* until the merchant receives the login token
and the user's information:

0. Before all this, the merchant has fetched the OpenID configuration from the well-known endpoint
   and cached it.

   See [.well-known](#openid-connect-discovery-endpoint).

1. The merchant initiates a login by calling the `authorization_endpoint` from .well-known.
   `GET {authorization_endpoint}?client_id={client_id}&response_type=code&scope={scopes}&state={state}&redirect_uri={redirect_uri}`

   See [Authorization endpoint](#oauth-20-authorize).

2. This will bring the user to the Vipps or MobilePay login screen, where they will consent to sharing
   information with the merchant. After consenting, the browser is redirected to the
   `redirect_uri` supplied by the merchant.
   `{redirect_uri}?code={code}&state={state}&scope={scopes}`

3. The merchant uses the `code`-parameter to obtain the login token.
   `POST {token_endpoint}` with `code={code}`, `grant_type=authorization_code`, and
   `redirect_uri={redirect_uri}` in the `application/x-www-form-urlencoded`-body.
   This returns (amongst others) an `access_token` that can be used to fetch userinfo.

   See [Token endpoint](#oauth-20-token).

4. To obtain userinfo, the merchant must do a GET to the `userinfo_endpoint` with the header:
   `Authorization: Bearer {access_token}`. This returns the information the user consented to sharing.

   See [Userinfo](#userinfo).

### Endpoints

#### OpenID connect discovery endpoint

| Environment | Base URL                                                                                 |
|-------------|------------------------------------------------------------------------------------------|
| Test        | `https://apitest.vipps.no/access-management-1.0/access/.well-known/openid-configuration` |
| Production  | `https://api.vipps.no/access-management-1.0/access/.well-known/openid-configuration`     |

The OpenID connect discovery endpoint can be used to retrieve configuration information for OpenID connect clients.
We recommend fetching these dynamically; however, the response from this endpoint rarely changes.
Therefore, it can and should be cached, so it's not fetched over the network on every login. The endpoint responds with a `Cache-Control: max-age=3600` header.

You can learn more at the [OIDC Standard](https://openid.net/specs/openid-connect-discovery-1_0.html).

Request:

[`GET:/access-management-1.0/access/.well-known/openid-configuration`][login-discoveropenid-endpoint]

Response:

Overview

| HTTP status        | Description                                               |
|--------------------|-----------------------------------------------------------|
| `200 OK`           | Request successful.                                       |
| `500 Server Error` | An internal Vipps MobilePay problem.                                |

Example response from the merchant test environment:

```json
{
  "issuer": "https://apitest.vipps.no/access-management-1.0/access/",
  "authorization_endpoint": "https://apitest.vipps.no/access-management-1.0/access/oauth2/auth",
  "token_endpoint": "https://apitest.vipps.no/access-management-1.0/access/oauth2/token",
  "jwks_uri": "https://apitest.vipps.no/access-management-1.0/access/.well-known/jwks.json",
  "subject_types_supported": [
    "public",
    "pairwise"
  ],
  "response_types_supported": [
    "code",
    "code id_token",
    "id_token",
    "token id_token",
    "token",
    "token id_token code"
  ],
  "claims_supported": [
    "sub"
  ],
  "grant_types_supported": [
    "authorization_code",
    "implicit",
    "client_credentials",
    "refresh_token"
  ],
  "response_modes_supported": [
    "query",
    "fragment"
  ],
  "userinfo_endpoint": "https://apitest.vipps.no/vipps-userinfo-api/userinfo",
  "scopes_supported": [
    "openid",
    "address",
    "name",
    "email",
    "phoneNumber",
    "nin",
    "birthDate",
  ],
  "token_endpoint_auth_methods_supported": [
    "client_secret_post",
    "client_secret_basic",
    "private_key_jwt",
    "none"
  ],
  "userinfo_signing_alg_values_supported": [
    "none",
    "RS256"
  ],
  "id_token_signing_alg_values_supported": [
    "RS256"
  ],
  "request_parameter_supported": true,
  "request_uri_parameter_supported": true,
  "require_request_uri_registration": true,
  "claims_parameter_supported": false,
  "revocation_endpoint": "https://apitest.vipps.no/access-management-1.0/access/oauth2/revoke",
  "backchannel_logout_supported": false,
  "backchannel_logout_session_supported": false,
  "frontchannel_logout_supported": false,
  "frontchannel_logout_session_supported": false,
  "end_session_endpoint": "https://apitest.vipps.no/access-management-1.0/access/oauth2/sessions/logout"
}
```

#### OpenID connect discovery URLs

| Operation                                           | Description                                                                         | Endpoints                                                |
|-----------------------------------------------------|-------------------------------------------------------------------------------------|----------------------------------------------------------|
| [OAuth 2.0 authorize](#oauth-20-authorize)          | Start an OAuth 2.0 authorization.                                                   | [`GET:/access-management-1.0/access/oauth2/auth`][access-auth-endpoint]               |
| [OAuth 2.0 token](#oauth-20-token)                  | Get an OAuth 2.0 access token.                                                      | [`POST:/access-management-1.0/access/oauth2/token`][access-token-endpoint]            |
| [Userinfo](#userinfo)                               | Returns information that the user has consented to share.                           | [`GET:/vipps-userinfo-api/userinfo`][userinfo-endpoint]  |
| [JSON web keys discovery](#json-web-keys-discovery) | Get JSON web keys to be used as public keys for verifying OpenID Connect ID Tokens. | [`GET:/.well-known/jwks.json`][login-wellknown-endpoint] |

#### OAuth 2.0 authorize

The `authorize` endpoint is a standard OIDC endpoint used for starting an
authorization. The client creates a request URI and directs the resource owner
to the constructed URI.

Request:

The client constructs the request URI by adding the following parameters to the
query component of the authorization endpoint URI using the
`application/x-www-form-urlencoded` format. The client directs the resource
owner to the constructed URI using an HTTP redirection response, or by other
means available to it via the user-agent.

| Query | Description | Required/Optional | Example |
| ----- | ---------------- |------------------- | ---------- |
| `response_type`        | Value MUST be set to `code`. | Required | `code` |
| `client_id`            | The client identifier, issued by Vipps MobilePay. | Required | `123456-test-client-id` |
| `redirect_uri`         | Redirect URI which the user agent is redirected to after finishing a login. Recommend to use universal links (Apple)/Asset links (Android), such as `https://example.com/app/callback`. If the URI is using a custom URL scheme, a path is required: `myapp://path-to-something`. See [API endpoints required from the merchant](#api-endpoints-required-from-the-merchant). | Required | `https://example.com/app/callback` |
| `scope`                | Scope of the access request, space-separated list. | Required | `openid email phoneNumber` |
| `state`                | An opaque value (e.g. a GUID) used by the client to maintain state between the request and callback. The authorization server includes this value when redirecting the user-agent back to the client. It must be at least 8 characters long to ensure sufficient entropy. In case of a too short state parameter the end-user will be redirected back to the merchant's site with an error. | Required | `123e4567-e89b-12d3-a456-426614174000` |
| `requested_flow`       | Request a specific flow for the user. See [Login from a mobile app](https://developer.vippsmobilepay.com/docs/APIs/login-api/api-guide/mobile-app-flows/README.md). | Optional | `app_to_app` or `app_to_app_v2` |
| `market`               | Supported values: `NO`, `DK`, `FI`, `SE`. The market where the Login integration is used helps us decide whether the Login client should appear with a Vipps  theme (for Norway and Sweden) or MobilePay  theme (for Denmark and Finland). | Optional | `NO` results in Vipps theme |
| `app_callback_uri`     | The target URI for automatic switch back to merchant app. Requires `requested_flow=app_to_app` or `requested_flow=app_to_app_v2`. | Optional | `https://example.com/app/callback` |
| `final_redirect_is_app`| Either `true` or `false`. If this is `true` we will enable some compatibility features to make sure the user is returned to the app. | Optional | `true` |
| `code_challenge_method`| Used for [PKCE](https://datatracker.ietf.org/doc/html/rfc7636), either `S256` or `plain`. Default value is `plain`. | Optional | `S256` |
| `code_challenge`       | Used for [PKCE](https://datatracker.ietf.org/doc/html/rfc7636). The value must be calculated based on the `code_verifier` later used towards the [token endpoint](#oauth-20-token). | Optional | `E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM` |
| `acr_values`           | Requires the user to authenticate via the Vipps or MobilePay app, even if they are remembered in the browser. The returned ID token will contain an `acr` claim that must be validated. Only available to merchants on the advanced pricing tier. See [In-app confirmation](https://developer.vippsmobilepay.com/docs/APIs/login-api/api-guide/in_app_confirmation.md). | Optional | `urn:vipps:acr:app_auth` |

For example, the client directs the user-agent to make the following HTTP request:

[`GET:/access-management-1.0/access/oauth2/auth?client_id={client_id}&response_type=code&scope={scopes}&state={state}&redirect_uri={redirect_uri}`][access-auth-endpoint]

You can test this by entering the URL into any browser. This will initiate the log in sequence.

See the step-by-step instructions in the
[quick start guide](https://developer.vippsmobilepay.com/docs/APIs/login-api/login-api-quick-start.md).

**Important**

URIs specified on the [business portal](https://portal.vippsmobilepay.com)
must be *exactly* the same as used in the API calls. Be extra careful with
trailing `/` and URL-encoded entities. If the URIs are not identical you will get
this error:

>The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client

Response:

If the resource owner grants the access request, the authorization server issues
an authorization code and delivers it to the client by adding the following
parameters to the query component of the redirection URI using the
`application/x-www-form-urlencoded` format.

| Query | Description                                                                                                                                                                                                                                                             |
|-------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `code`  | The authorization code generated by the authorization server. This code should be sent with the subsequent `/token` request.  The client MUST NOT use the authorization code more than once. The authorization code is bound to the client identifier and redirect URI. |
| `state` | The exact value received from the client during the authorization request.                                                                                                                                                                                              |
| `scope` | The scopes that the end user has consented to. This list will always be the same as in the request query as end users are not allowed to remove individual scopes when they give consent.                                                                               |

For example, the authorization server redirects the user-agent by sending the
following HTTP response:

```text
HTTP/1.1 302 Found
Location: https://example.com/callback?code={code}&state={state}&scope={scopes}
```

If the resource owner declines the access request, or an error occurs, the authorization server adds the following parameters to the query component of the
redirection URI using the `application/x-www-form-urlencoded` format. More details in [Error handling](#error-handling)

For more general information see the standard specifications
[OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html#AuthResponse) and [RFC-6749 section 4.1.1-4.1.2](https://tools.ietf.org/html/rfc6749#section-4.1.1).

#### OAuth 2.0 token

The token endpoint is a standard OIDC endpoint used for requesting Access and
ID Tokens. The client constructs the request by adding the parameters described
below to the HTTP body by using the `application/x-www-form-urlencoded` format.

Request:

Headers

| Header         | Description                         |
|----------------|-------------------------------------|
| `Content-Type`   | `application/x-www-form-urlencoded` |
| `Authorization`  | `Basic {Client Credentials}`        |

The `Client Credentials` is a base 64 encoded string consisting of the `client_id`
and secret issued by Vipps MobilePay joined by `:`.

Example in JavaScript:

```javascript
var client_id = 123456-test-4a3d-a47c-412136fd0871
var client_secret = AAAAAAAAAAAAAAAAAAAAAA==

var wordArrayAzp = CryptoJS.enc.Utf8.parse(client_id + ":" + client_secret);
var client_credentials = CryptoJS.enc.Base64.stringify(wordArrayAzp);
```

Form content:

| Key | Description |
|-----|-------------|
| `grant_type`   | Value MUST be authorization_code.|
| `code`         | The authorization code received as a query parameter on the `redirect_uri` from the authorization server.|
| `redirect_uri` | Redirect URI which the user agent is redirected to after finishing a login. Recommend to use universal links (Apple)/Asset links (Android), such as `https://example.com/app/callback`. If the URI is using a custom URL scheme, a path is required: `myapp://path-to-something`. See [API endpoints required from the merchant](#api-endpoints-required-from-the-merchant). This field is required for OIDC flows, i.e. regular Vipps MobilePay logins. |

[`POST:/access-management-1.0/access/oauth2/token`][access-token-endpoint]

Response:

| HTTP status         | Description                 |
|---------------------|-----------------------------|
| `200 OK`            | Request successful.         |
| `401 Unauthorized`  | Invalid credentials.        |
| `500 Server Error`  | An internal Vipps MobilePay problem.  |

Example response:

```json
{
  "access_token": "hel39XaKjGH5tkCvIENGPNbsSHz1DLKluOat4qP-A4.WyV61hCK1E2snVs1aOvjOWZOXOayZad0K-Qfo3lLzus",
  "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6InB1YmxpYzo4MGYzYzM0YS05Nzc5LTRlMWUtYjY0NS0xMTdmM2I3NzFhZjgiLCJ0eXAiOiJKV1QifQ.eyJhdF9oYXNoIjoidHlGbkgyMFRPbVBaa2dKVThlNWlLdyIsImF1ZCI6WyJ2aXBwcy1pbnRlZ3JhdGlvbiJdLCJhdXRoX3RpbWUiOjE1NTczMTkyOTYsImV4cCI6MTU1NzMyMjkzOCwiaWF0IjoxNTU3MzE5MzM4LCJpc3MiOiJodHRwczovL2FwaXRlc3QudmlwcHMubm8vYWNjZXNzLW1hbmFnZW1lbnQtMS4wL2FjY2Vzcy8iLCJqdGkiOiI2MmE4NWU1Ni0zZDQ1LTRjN2UtYTA1NS00NjkzMjA5MzI1N2EiLCJub25jZSI6IiIsInJhdCI6MTU1NzMxOTI1NSwic3ViIjoiYzA2YzRhZmUtZDllMS00YzVkLTkzOWEtMTc3ZDc1MmEwOTQ0In0.OljG0W_TCfxkrRntj_5He3U0PH94SDZvlK-dvUJe8H5jj8QSiSnqiv65kyzxdr8Bq1MwG7a6Mtlnn4MoL8AyxKUVe6s81CNaYmwaHsWLw2Z2JmiPn5_X4lEy1nHVDX3R7lFKDQqFLSGnGNPU9bACj-Si18LBR-qv060wEj3b1ShrVeUIZCL1Yhxb6cIGl_8RivRto9dBrzggyOlVTtmoPrm9TLYF7UGWjlbmHTqpBWsCQIOeQqgs7RmSBt5k3O9nmP7guVxo5MWv_2Z0XuCqobLDDXJ29Rk_W6d79y-lPzq_TedNb_lCdVJF7u9qDYFbIPuQwXp26CeIJcR-nc-t0qEoNmLru_x-9Z8dCjjzkZbWqyNsNedQU1zt0WFbHjRkodVoHNcRZVT5W5hCe54lmZ6lUqyKwHW0_3Rpd2CI6lPdCOhC-Tze5cUDfb8jT_0OZqCI_wAuWvb6_4VeHqhvUav6Mh6d7AxNJQYG6BAJo9TzyrG7ho4mSpb2wWMr8gmRi8pTQbqa40whPqptpiz_j4AHcsrRckjYONU0USKlnNcBGc24M4sprcLZ6vxFqDYmDoZwUDRdZWRpUbqm_nCmCKb20Z6l5O7h32KvOApopJe2NIeAynli3Nl05QVGOdoT1mZDLYXbtyb0b_4qhRflySr6gaczcf2ovUKAToKNs_4",
  "expires_in": 3599,
  "scope": "openid",
  "token_type": "bearer"
}
```

#### Userinfo

The [`GET:/vipps-userinfo-api/userinfo`][userinfo-endpoint] endpoint returns the payload with the information that the user has consented to share, which is provided in
the OAuth 2.0 access token.

You can learn more at [OIDC Standard](https://openid.net/specs/openid-connect-core-1_0.html#UserInfo).

Request:

Headers:

| Header         | Description              |
|----------------|--------------------------|
| Authorization  | `Bearer {Access Token}`  |

The access token is received on a successful request to the [token endpoint](#oauth-20-token).

[`GET:/vipps-userinfo-api/userinfo`][userinfo-endpoint]

Response:

Overview

| HTTP status         | Description                 |
|---------------------|-----------------------------|
| `200 OK`            | Request successful.         |
| `401 Unauthorized`  | Invalid credentials.        |
| `500 Server Error`  | An internal Vipps MobilePay problem.  |

#### Standard example response

```json
{
    "sub": "c06c4afe-d9e1-4c5d-939a-177d752a0944",
    "birthdate": "1815-12-10",
    "email": "user@example.com",
    "email_verified": true,
    "nin": "10121550047",
    "name": "Ada Lovelace",
    "given_name": "Ada",
    "family_name": "Lovelace",
    "sid": "7d78a726-af92-499e-b857-de263ef9a969",
    "phone_number": "4712345678",
    "address": {
        "street_address": "Suburbia 23",
        "postal_code": "2101",
        "region": "OSLO",
        "country": "NO",
        "formatted": "Suburbia 23\\n2101 OSLO\\nNO",
        "address_type": "home"
    },
    "other_addresses": [
        {
            "street_address": "Fancy Office Street 2",
            "postal_code": "0218",
            "region": "OSLO",
            "country": "NO",
            "formatted": "Fancy Office Street 2\\n0218 OSLO\\nNO",
            "address_type": "work"
        },
        {
            "street_address": "Summer House Lane 14",
            "postal_code": "1452",
            "region": "OSLO",
            "country": "NO",
            "formatted": "Summer House Lane 14\\n1452 OSLO\\nNO",
            "address_type": "other"
        }
    ]
}
```

#### JSON web keys Discovery

This endpoint returns JSON Web Keys to be used as public keys for verifying OpenID Connect ID Tokens.

Request:

[`GET:/access-management-1.0/access/.well-known/jwks.json`][login-wellknown-endpoint]

Response:

Overview

| HTTP status         | Description                |
|---------------------|----------------------------|
| `200 OK`            | Request successful.        |
| `500 Server Error`  | An internal Vipps MobilePay problem. |

Examples:
*200 response*

```json
{
    "keys": [
        {
            "use": "sig",
            "kty": "RSA",
            "kid": "public:80f3c34a-9779-4e1e-b645-117f3b771af8",
            "alg": "RS256",
            "n": "n4kytA_ZeI3Znl96b-zteWmrSHjRmXnvLmACQ4W_BVRTtuhumuoLpOpavUcEOhajbLKqBrANC0dd7ABtL92gHRoVRp8VMSNBG6ykuD04gevxqgm2Gz1mGineWBrjINwY-WboPMqgyZLLKw-JjZ6EqHm67TnWxrKjk3135tGILWvrTJ6ykglGpfH0jpGtEOS6VUuSWeW5VitEGeOFDwWja4mYXZbfGICtKnD6LZOM8sFKyC9diBmDXuXZvxdwdBfVh9JvWMaZ5bJ_mv4iJ0qU0FM1yginRMLXY3MOxwLSLSQjmDPV8NZecUsK-UEfpJl7lvLdEFqKCdqQxkEEyLPMq_rM50F5QIbKa0BYoa973-OR9cJ-XQkLNCtF5i003Z3V-5c7N3xBNlpGYsp4CCvv--zFpxvRZ0k-axgu1Loj1eOZRuX1DL86iTQ6YXcBGPYlRkRNJOn7mkRV8wn8kp_DMlzJ7bgE-NFEA32wFrEimPCrGUfdNdjn6gMsWKcbiHiM4NlIDrCNPiD2CVPrHGuVex8R0cpKU0Cvxc8mXqvDc-VJbrqrRNPbZJh0Zoz4wfK9LESdYGAah9PhgHg5LDFHmhT0W3FPmy1Gmfk2ino4PryJ_rDXe0WT84IEGV9YEM631gDerS63D1dKvTP01YT5sd2Ymn9eptH9grvFeOhuvz0",
            "e": "AQAB"
        }
    ]
}
```

This operation does not require authentication.

#### API endpoints required from the merchant

The following endpoints are to be implemented by merchants, in order for us
to redirect the resource owner to them.

#### Receive authentication result

After a successful authentication, the user agent is redirected to this endpoint
with the following parameters added to the query component. This URI must
be pre-registered with us, and it must be supplied as a query parameter on calls to the
[OAuth2 authorize endpoint](#oauth-20-authorize).

| Parameter | Description |
|-----------|-------------|
| `code`    | The authorization code generated by the authorization server. The client MUST NOT use the authorization code more than once. The authorization code is bound to the client identifier and redirection URI. |
| `state`   | The exact value received from the client during the authorization request.|

Example:

```text
HTTP/1.1 302 Found
Location: https://example.com/callback?code={code}&state={state}
```

### Error handling

If the user cancels the login or an error occurs, the user agent is redirected
to the authentication result endpoint with the following parameters
added to the query component.

| Parameter            | Description |
|----------------------|-------------|
| `error`              | Standard [OAuth2](https://tools.ietf.org/html/rfc6749#section-4.1.2.1) or [OIDC](https://openid.net/specs/openid-connect-core-1_0.html#AuthError) error code.  |
| `error_description`  | A short text providing additional information on the error that occurred. |
| `state`              | The exact value received from the client during the authorization request. |

#### Custom error codes

In addition to the standard errors defined in [OAuth2](https://tools.ietf.org/html/rfc6749#section-4.1.2.1) and [OIDC](https://openid.net/specs/openid-connect-core-1_0.html#AuthError), Login also has some custom error codes that you might see on the redirect:

| error_code                         | Description                                                      |
|------------------------------------|------------------------------------------------------------------|
| `access_denied`                    | User cancelled the login                                         |
| `server_error`                     | Something went wrong, please try again                           |
| `login_required`                   | User must log in with interaction                                |
| `invalid_app_callback_uri`         | The app callback URI is not on a valid format                    |
| `app_callback_uri_not_registered`  | The app callback URI is not registered as a redirect URI         |
| `outdated_app_version`             | The user's Vipps or MobilePay app version is too old and needs to be updated  |
| `wrong_challenge`                  | The user selected the wrong challenge                            |
| `unknown_reject_reason`            | Something went wrong. Reject reason is unknown.                  |

There may be other errors, so integrators must be able to handle undocumented errors gracefully.

Example:

```text
HTTP/1.1 302 Found
Location: https://example.com/callback?error=access_denied&error_description=user%20cancelled%20the%20login?state={state}
```

If a fatal error occurs where the user can't be redirected back to the merchant, a generic Vipps or MobilePay styled error page will be shown containing a brief error description.

## Browser flow marketing consents

The merchant may choose to include the `delegatedConsents` scope to collect consents from the user.
If the scope is included in the request, the user will be asked to give consents according to merchant specifications. In the browser flow this happens only on the first login.

* [Configure the marketing consents.](https://developer.vippsmobilepay.com/docs/APIs/login-api/api-guide/collecting-consents.md)
* Follow the [call by call guide](#call-by-call), but with the addition of the `delegatedConsents` scope in the initial request. This will prompt the user to give consent to the merchant's marketing consents.
* The first time the user logs in the userinfo response will contain the user's consent status on the format shown in the [Userinfo response example](#example-response-with-marketing-consents).
* Later logins will not prompt the user for consent again or contain data on the userinfo response, unless the merchant re-configures marketing consents in the business portal.

Marketing consents are remembered for the user, so they only need to approve them once.
This means that if the user has already approved the consents, they will not see the screen again.
You can configure that previously consented users review and consent to new terms through the business portal when you save a new [Marketing consents](https://developer.vippsmobilepay.com/docs/APIs/login-api/api-guide/collecting-consents.md) configuration.

### Example response with marketing consents

Note the `delegatedConsents` object will only be present on the first login.

 ```json
 {
   "family_name": "Heyerdahl",
   "given_name": "Tor Fos",
   "name": "Tor Fos Heyerdahl",
   "other_addresses": [],
   "sid": "qwieuhwqiuhdiuwqh",
   "sub": "f350ef33-22e2-47d0-9f47-12345667",
   "delegatedConsents" : {
     "language" : "EN",
     "heading" : "Give consent",
     "termsDescription" : "By confirming, you accept oidc-testclient's terms of membership. They are responsible for processing the consents. You can withdraw them at any time on their website.",
     "confirmConsentButtonText" : "Confirm",
     "links" : {
       "termsLinkText" : "Read the terms of use.",
       "termsLinkUrl" : "https://vippsmobilepay.com/en-NO/legal/terms-and-conditions",
       "privacyStatementLinkText" : "Read the privacy policy.",
       "privacyStatementLinkUrl" : "https://vippsmobilepay.com/en-NO/terms-privacy"
     },
     "timeOfConsent" : "2022-11-23T11:40:13Z",
     "consents" : [ {
       "id" : "email",
       "accepted" : true,
       "required" : true,
       "textDisplayedToUser" : "Receive offers via email"
     }, {
       "id" : "sms",
       "accepted" : true,
       "required" : false,
       "textDisplayedToUser" : "Receive offers via SMS"
     }, {
       "id" : "digital",
       "accepted" : true,
       "required" : false,
       "textDisplayedToUser" : "I would like to receive digital marketing"
     }, {
       "id" : "personal",
       "accepted" : true,
       "required" : false,
       "textDisplayedToUser" : "Get customized offers"
     } ]
   }
 }
 ```

[login-wellknown-endpoint]: https://developer.vippsmobilepay.com/redocusaurus/login-swagger-id.yaml
[login-discoveropenid-endpoint]: https://developer.vippsmobilepay.com/redocusaurus/login-swagger-id.yaml
[userinfo-endpoint]: https://developer.vippsmobilepay.com/redocusaurus/login-swagger-id.yaml
[access-auth-endpoint]: https://developer.vippsmobilepay.com/redocusaurus/login-swagger-id.yaml
[access-token-endpoint]: https://developer.vippsmobilepay.com/redocusaurus/login-swagger-id.yaml

> **Full site overview:** For every page in this documentation, read [https://developer.vippsmobilepay.com/llms.txt](https://developer.vippsmobilepay.com/llms.txt).
